package socket.nio;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
import org.junit.Test;

import java.net.InetSocketAddress;

public class MyNetty {
  
  @Test
  public void clientMode() throws InterruptedException {
    // 实例化 事件循环 group
    NioEventLoopGroup eventExecutors = new NioEventLoopGroup(1);
    
    // 通过 nio 创建 client
    NioSocketChannel client = new NioSocketChannel();
    eventExecutors.register(client);
    
    // 等待响应
    ChannelPipeline pipeline = client.pipeline();
    // 添加处理器
    pipeline.addLast(new MyInHandler());
    
    // 连接 ip以及端口
    ChannelFuture connect = client.connect(new InetSocketAddress("localhost", 8080));
    // 等待连接成功
    ChannelFuture sync = connect.sync();
    
    // 创建 临时 buffer内容
    ByteBuf byteBuf = Unpooled.copiedBuffer("hello buffer".getBytes());
    ChannelFuture channelFuture = client.writeAndFlush(byteBuf);
    // 等待发生成功
    channelFuture.sync();
    
    sync.channel().closeFuture().sync();
    System.out.println("client close ......");
  }
  
  @Test
  public void serverMode() throws InterruptedException {
    // 基于 nio 创建 event loop
    NioEventLoopGroup eventExecutors = new NioEventLoopGroup(1);
    
    // 创建 server
    NioServerSocketChannel server = new NioServerSocketChannel();
    eventExecutors.register(server);
    
    // 等待 响应
    ChannelPipeline pipeline = server.pipeline();
    // 添加 server 以及client 响应
    pipeline.addLast(new MyAcceptHandler(eventExecutors, new ChannelInit()));
    
    // 绑定 地址以及端口
    ChannelFuture channel = server.bind(new InetSocketAddress("localhost", 8080));
    // 等待 bind 完成
    channel.sync().channel().closeFuture().sync();
    System.out.println("server close ......");
  }
  
  @Test
  public void nettyClient() throws InterruptedException {
    // 实例化 event loop
    NioEventLoopGroup eventExecutors = new NioEventLoopGroup(1);
    // 这是一个启动类
    Bootstrap bootstrap = new Bootstrap();
    
    ChannelFuture connect = bootstrap.group(eventExecutors)
        // 设置 SocketChannel 类
        .channel(NioSocketChannel.class)
        .handler(new ChannelInitializer<SocketChannel>() {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            pipeline.addLast(new MyInHandler());
          }
        }).connect(new InetSocketAddress("localhost", 8080));
    
    // 这里拿到 客户端
    Channel client = connect.sync().channel();
    
    ByteBuf byteBuf = Unpooled.copiedBuffer("hello buffer".getBytes());
    ChannelFuture channelFuture = client.writeAndFlush(byteBuf);
    channelFuture.sync();
    
    client.closeFuture().sync();
  }
  
  @Test
  public void nettyServer() throws InterruptedException {
    NioEventLoopGroup eventExecutors = new NioEventLoopGroup(1);
    // server bootstrap 启动类
    ServerBootstrap serverBootstrap = new ServerBootstrap();
    
    ChannelFuture serverFuture = serverBootstrap.group(eventExecutors, eventExecutors)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>() {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            pipeline.addLast(new MyInHandler());
          }
        }).bind(new InetSocketAddress("localhost", 8080));
    
    serverFuture.sync().channel().closeFuture().sync();
  }
}

@ChannelHandler.Sharable
class ChannelInit extends ChannelInboundHandlerAdapter {
  @Override
  public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    // 拿到 client 客户端
    Channel client = ctx.channel();
    ChannelPipeline pipeline = client.pipeline();
    pipeline.addLast(new MyInHandler());
    // 删除共同的
    ctx.pipeline().remove(this);
  }
}

class MyAcceptHandler extends ChannelInboundHandlerAdapter {
  private final EventLoopGroup selector;
  private final ChannelHandler channelHandler;
  
  public MyAcceptHandler(EventLoopGroup selector, ChannelHandler channelHandler) {
    this.selector = selector;
    this.channelHandler = channelHandler;
  }
  
  @Override
  public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    System.out.println("my accept channel registered");
  }
  
  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    // 拿到 客户端
    SocketChannel client = (SocketChannel) msg;
    ChannelPipeline pipeline = client.pipeline();
    
    pipeline.addLast(this.channelHandler);
    this.selector.register(client);
  }
}

class MyInHandler extends ChannelInboundHandlerAdapter {
  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    ByteBuf buf = (ByteBuf) msg;
    
    // 表示 读取内容
    CharSequence str = buf.getCharSequence(0, buf.readableBytes(), CharsetUtil.UTF_8);
    System.out.println("read: " + str);
    
    // 再次往回写
    ctx.writeAndFlush(buf);
  }
  
  @Override
  public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    System.out.println("channel registered ...");
  }
  
  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    System.out.println("channel active ...");
  }
}
